﻿using System;
using System.Data;
using System.Configuration;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using System.Text;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Reflection;

namespace Microsoft.SqlCommunity.SQLRSS
{
    /// <summary>
    /// This class contains some general purpose methods which are used by one or more other main classes in the server application.
    /// </summary>
    public class Utility
    {
        /// <summary>
        /// Take a list of items of type TElement and output them to the StringBuilder sb, separating value of those elements with
        /// the specified seperator.  The value of each element is computed by the supplied function converter, which takes a TElement and
        /// turns it into a string to be output to the StringBuilder.
        /// </summary>
        /// <typeparam name="TElement">What type of elements we'll find in the supplied list</typeparam>
        /// <param name="seperator">What to separate each element of the supplied list with</param>
        /// <param name="list">What list of items to output</param>
        /// <param name="converter">How to convert an element into a string value to be output</param>
        /// <param name="sb">Where to send the output</param>
        public static void OutputStringJoin<TElement>(string seperator, List<TElement> list, Func<TElement, string> converter, StringBuilder sb)
        {
            bool first = true;
            foreach (TElement element in list)
            {
                if (first)
                    first = false;
                else
                    sb.Append(seperator);
                sb.Append(converter(element));
            }
        }

        /// <summary>
        /// Exchange objects of type TItem between any place1 and place2.  A place could be a local variable or data member, for example.
        /// </summary>
        /// <typeparam name="TItem">What type of objects are being exchanged</typeparam>
        /// <param name="place1">One place involved in the exchange.</param>
        /// <param name="place2">Another place involved in the exchange.</param>
        public static void Swap<TItem>(ref TItem place1, ref TItem place2)
        {
            TItem temp;
            temp = place1;
            place1 = place2;
            place2 = temp;
        }
    }

    /// <summary>
    /// This class is used to log exception to an application specific error log.
    /// </summary>
    public class Logger
    {
        private const string _SourceName = "FeedMap";
        private const string _LogName = "FeedMapErrors";
        private const int _RetryCount = 10;

        EventLog _WindowsEventLog;

        private static Object LoggerClassLock = new Object();
        private static Logger _current = null;

        public static Logger Current
        {
            get 
            {
                if (_current == null)
                    lock (LoggerClassLock)
                    {
                        if (_current == null)
                            _current = new Logger();
                    }
                return _current; 
            }
        }

        public Logger()
        {
            // Create the source, if it does not already exist.
            if (!EventLog.SourceExists(_SourceName))
            {
                //An event log source should not be created and immediately used.
                //There is a latency time to enable the source, it should be created
                //prior to executing the application that uses the source.
                EventLog.CreateEventSource(_SourceName, _LogName);
                int i = 0;
                while (!EventLog.SourceExists(_SourceName))
                {
                    Thread.Sleep(1000);
                    if (i++ > _RetryCount)
                    {
                        Console.WriteLine("Error: Failed to create {0} event source. Exiting.", _SourceName);
                        Environment.Exit(-1);
                    }
                }
            }

            // Create an EventLog instance and assign its source.
            _WindowsEventLog = new EventLog();
            _WindowsEventLog.Source = _SourceName;

        }

        /// <summary>
        /// Add a message to the error log
        /// </summary>
        /// <param name="entryType">What type of message</param>
        /// <param name="formatString">The message itself as a (real, .net) format string</param>
        /// <param name="args">Any parameters needed for the format string.</param>
        public void LogMessage(EventLogEntryType entryType, string formatString, params string[] args)
        {
            lock (_current)
            {
                _WindowsEventLog.WriteEntry(string.Format(formatString, args), entryType);
            }
        }

    }
}
